import { Context } from 'koa';
import { AppContext, UserType } from '@/types';
import { validate } from '@/utils/validator';
import { success } from '@/utils/response';
import logger from '@/utils/logger';
import Joi from 'joi';
import Menu, { MenuType } from '@/models/Menu.model';
import { Op } from 'sequelize';

interface CreateMenuData {
  parentId?: string | null;
  name: string;
  title: string;
  english?: string;
  type: MenuType;
  path?: string;
  component?: string;
  icon?: string;
  permission?: string;
  orderNum?: number;
  visible?: boolean;
  status?: boolean;
  cache?: boolean;
  redirect?: string;
}

interface UpdateMenuData {
  parentId?: string | null;
  title?: string;
  english?: string;
  type?: MenuType;
  path?: string;
  component?: string;
  icon?: string;
  permission?: string;
  orderNum?: number;
  visible?: boolean;
  status?: boolean;
  cache?: boolean;
  redirect?: string;
}

/**
 * 菜单管理控制器
 */
class MenuController {
  /**
   * 创建菜单
   */
  async create(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;

    const schema = Joi.object({
      parentId: Joi.string().uuid().optional().allow(null),
      name: Joi.string().required().max(100).messages({
        'string.empty': '菜单名称不能为空',
        'any.required': '菜单名称是必填项',
      }),
      title: Joi.string().required().max(100).messages({
        'string.empty': '菜单标题不能为空',
        'any.required': '菜单标题是必填项',
      }),
      english: Joi.string().max(100).optional().allow(null, ''),
      type: Joi.string().valid('directory', 'menu', 'button').required(),
      path: Joi.string().max(200).optional().allow(null, ''),
      component: Joi.string().max(200).optional().allow(null, ''),
      icon: Joi.string().max(100).optional().allow(null, ''),
      permission: Joi.string().max(200).optional().allow(null, ''),
      orderNum: Joi.number().integer().optional().default(0),
      visible: Joi.boolean().optional().default(true),
      status: Joi.boolean().optional().default(true),
      cache: Joi.boolean().optional().default(false),
      redirect: Joi.string().max(200).optional().allow(null, ''),
    });

    const data = await validate<CreateMenuData>(ctx.request.body as any, schema);

    try {
      // 检查菜单名称是否已存在
      const existing = await Menu.findOne({
        where: { name: data.name },
      });

      if (existing) {
        ctx.throw(400, '菜单名称已存在');
      }

      // 超级管理员创建的是系统菜单，租户管理员创建的是租户菜单
      const menu = await Menu.create({
        ...data,
        tenantId: user!.type === UserType.SUPER_ADMIN ? null : user!.tenantId,
      } as any);

      logger.info(`菜单创建成功: ${menu.name} by ${user!.email}`);
      success(ctx, menu, '菜单创建成功');
    } catch (error) {
      logger.error('菜单创建失败:', error);
      ctx.throw(500, '菜单创建失败');
    }
  }

  /**
   * 获取菜单树
   */
  async tree(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;

    try {
      const where: any = {
        status: true,
      };

      // 非超级管理员只能看到系统菜单和自己租户的菜单
      if (user!.type !== UserType.SUPER_ADMIN) {
        where[Op.or] = [
          { tenantId: null },
          { tenantId: user!.tenantId },
        ];
      }

      const menus = await Menu.findAll({
        where,
        order: [['orderNum', 'ASC'], ['createdAt', 'ASC']],
      });

      // 构建树形结构
      const tree = this.buildTree(menus, null);

      success(ctx, tree);
    } catch (error) {
      logger.error('获取菜单树失败:', error);
      ctx.throw(500, '获取菜单树失败');
    }
  }

  /**
   * 获取用户菜单（根据权限过滤）
   */
  async userMenus(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;

    try {
      // 超级管理员返回所有菜单
      if (user!.type === UserType.SUPER_ADMIN) {
        const menus = await Menu.findAll({
          where: {
            status: true,
            visible: true,
            type: { [Op.ne]: 'button' }, // 排除按钮
          },
          order: [['orderNum', 'ASC'], ['createdAt', 'ASC']],
        });

        const tree = this.buildTree(menus, null);
        success(ctx, tree);
        return;
      }

      // 普通用户根据角色权限返回菜单
      if (!user!.roleId) {
        success(ctx, []);
        return;
      }

      const Permission = (await import('@/models/Permission.model')).default;
      const RolePermission = (await import('@/models/RolePermission.model')).default;

      // 获取用户权限
      const rolePermissions = await RolePermission.findAll({
        where: { roleId: user!.roleId },
      });

      const permissionIds = rolePermissions.map((rp: any) => rp.permissionId);
      const permissions = await Permission.findAll({
        where: { id: permissionIds },
      });

      const userPermissions = permissions.map((p: any) => `${p.resource}:${p.action}`);

      // 获取菜单
      const where: any = {
        status: true,
        visible: true,
        type: { [Op.ne]: 'button' },
        [Op.or]: [
          { tenantId: null },
          { tenantId: user!.tenantId },
        ],
      };

      const menus = await Menu.findAll({
        where,
        order: [['orderNum', 'ASC'], ['createdAt', 'ASC']],
      });

      // 过滤有权限的菜单
      const filteredMenus = menus.filter((menu: any) => {
        // 目录不需要权限
        if (menu.type === 'directory') {
          return true;
        }
        // 没有配置权限的菜单默认显示
        if (!menu.permission) {
          return true;
        }
        // 检查是否有权限
        return userPermissions.includes(menu.permission);
      });

      const tree = this.buildTree(filteredMenus, null);
      success(ctx, tree);
    } catch (error) {
      logger.error('获取用户菜单失败:', error);
      ctx.throw(500, '获取用户菜单失败');
    }
  }

  /**
   * 获取用户按钮权限
   */
  async userButtons(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;

    try {
      // 超级管理员返回所有按钮
      if (user!.type === UserType.SUPER_ADMIN) {
        const buttons = await Menu.findAll({
          where: {
            status: true,
            type: 'button',
          },
        });

        const buttonPermissions = buttons.map((btn: any) => ({
          name: btn.name,
          permission: btn.permission,
        }));

        success(ctx, buttonPermissions);
        return;
      }

      // 普通用户根据角色权限返回按钮
      if (!user!.roleId) {
        success(ctx, []);
        return;
      }

      const RolePermission = (await import('@/models/RolePermission.model')).default;
      const Permission = (await import('@/models/Permission.model')).default;

      // 获取用户权限
      const rolePermissions = await RolePermission.findAll({
        where: { roleId: user!.roleId },
      });

      const permissionIds = rolePermissions.map((rp: any) => rp.permissionId);
      const permissions = await Permission.findAll({
        where: { id: permissionIds },
      });

      const userPermissions = permissions.map((p: any) => `${p.resource}:${p.action}`);

      // 获取按钮
      const buttons = await Menu.findAll({
        where: {
          status: true,
          type: 'button',
          [Op.or]: [
            { tenantId: null },
            { tenantId: user!.tenantId },
          ],
        },
      });

      // 过滤有权限的按钮
      const filteredButtons = buttons
        .filter((btn: any) => !btn.permission || userPermissions.includes(btn.permission))
        .map((btn: any) => ({
          name: btn.name,
          permission: btn.permission,
        }));

      success(ctx, filteredButtons);
    } catch (error) {
      logger.error('获取用户按钮权限失败:', error);
      ctx.throw(500, '获取用户按钮权限失败');
    }
  }

  /**
   * 获取菜单列表（平铺）
   */
  async list(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;

    try {
      const where: any = {};

      // 非超级管理员只能看到系统菜单和自己租户的菜单
      if (user!.type !== UserType.SUPER_ADMIN) {
        where[Op.or] = [
          { tenantId: null },
          { tenantId: user!.tenantId },
        ];
      }

      const menus = await Menu.findAll({
        where,
        order: [['orderNum', 'ASC'], ['createdAt', 'ASC']],
      });

      success(ctx, menus);
    } catch (error) {
      logger.error('获取菜单列表失败:', error);
      ctx.throw(500, '获取菜单列表失败');
    }
  }

  /**
   * 获取菜单详情
   */
  async detail(ctx: Context) {
    const { id } = ctx.params;

    try {
      const menu = await Menu.findByPk(id);

      if (!menu) {
        ctx.throw(404, '菜单不存在');
      }

      success(ctx, menu);
    } catch (error) {
      logger.error('获取菜单详情失败:', error);
      ctx.throw(500, '获取菜单详情失败');
    }
  }

  /**
   * 更新菜单
   */
  async update(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;
    const { id } = ctx.params;

    const schema = Joi.object({
      parentId: Joi.string().uuid().optional().allow(null),
      title: Joi.string().max(100).optional(),
      english: Joi.string().max(100).optional().allow(null, ''),
      type: Joi.string().valid('directory', 'menu', 'button').optional(),
      path: Joi.string().max(200).optional().allow(null, ''),
      component: Joi.string().max(200).optional().allow(null, ''),
      icon: Joi.string().max(100).optional().allow(null, ''),
      permission: Joi.string().max(200).optional().allow(null, ''),
      orderNum: Joi.number().integer().optional(),
      visible: Joi.boolean().optional(),
      status: Joi.boolean().optional(),
      cache: Joi.boolean().optional(),
      redirect: Joi.string().max(200).optional().allow(null, ''),
    });

    const data = await validate<UpdateMenuData>(ctx.request.body as any, schema);

    try {
      const menu = await Menu.findByPk(id);

      if (!menu) {
        ctx.throw(404, '菜单不存在');
      }

      // 检查是否可以修改
      if (menu.tenantId && menu.tenantId !== user!.tenantId && user!.type !== UserType.SUPER_ADMIN) {
        ctx.throw(403, '无权修改此菜单');
      }

      // 检查父菜单循环引用
      if (data.parentId && data.parentId === id) {
        ctx.throw(400, '不能将自己设置为父菜单');
      }

      await menu.update(data as any);

      logger.info(`菜单更新成功: ${menu.name} by ${user!.email}`);
      success(ctx, menu, '菜单更新成功');
    } catch (error) {
      logger.error('菜单更新失败:', error);
      ctx.throw(500, '菜单更新失败');
    }
  }

  /**
   * 删除菜单
   */
  async delete(ctx: Context) {
    const appCtx = ctx as AppContext;
    const { user } = appCtx.state;
    const { id } = ctx.params;

    try {
      const menu = await Menu.findByPk(id);

      if (!menu) {
        ctx.throw(404, '菜单不存在');
      }

      // 检查是否可以删除
      if (menu.tenantId && menu.tenantId !== user!.tenantId && user!.type !== UserType.SUPER_ADMIN) {
        ctx.throw(403, '无权删除此菜单');
      }

      // 检查是否有子菜单
      const childCount = await Menu.count({
        where: { parentId: id },
      });

      if (childCount > 0) {
        ctx.throw(400, `该菜单下还有 ${childCount} 个子菜单，无法删除`);
      }

      await menu.destroy();

      logger.info(`菜单删除成功: ${menu.name} by ${user!.email}`);
      success(ctx, null, '菜单删除成功');
    } catch (error) {
      logger.error('菜单删除失败:', error);
      ctx.throw(500, '菜单删除失败');
    }
  }

  /**
   * 构建树形结构
   */
  private buildTree(menus: any[], parentId: string | null): any[] {
    const tree: any[] = [];

    for (const menu of menus) {
      if (menu.parentId === parentId) {
        const children = this.buildTree(menus, menu.id);
        const node = {
          ...menu.toJSON(),
          children: children.length > 0 ? children : undefined,
        };
        tree.push(node);
      }
    }

    return tree;
  }
}

export default new MenuController();

